<template>
    <!-- 暂支持单个上传，批量上传todo isApp-->
    <app-uploader @on-app-success="onAppSuccess" v-if="isApp()" :multiple="multiple">
        <slot>
            <van-button icon="plus" type="primary">上传文件</van-button>
        </slot>
    </app-uploader>
    <van-uploader
        :maxCount="maxCount"
        :accept="uploaderAccept"
        :multiple="multiple"
        :before-read="onBeforeRead"
        :after-read="onAfterRead"
        v-else
    >
        <slot>
            <van-button icon="plus" type="primary">上传文件</van-button>
        </slot>
    </van-uploader>
</template>

<script>
import { defineComponent, ref, computed, watch, onMounted } from 'vue';
import createUploader from '@/lib/uploader-client';
import { getFileSuffix, formatFileSize } from './utils/helper';
import { v4 as uuid } from 'uuid';
import { useStore } from 'vuex';
import { Toast } from 'vant';
import AppUploader from './app-uploader.vue';
import { isApp, isAndroid } from '@/lib/judge-env.js';

const Status = {
    Prepare: 0,
    Processing: 1,
    Success: 2,
    Error: 3,
    Remove: 9
};
/**
 * emit事件说明
 * ('on-before-upload') 上传前钩子，可在此开启loading
 * ('on-success')(materialId,material) 上传成功, 有素材id但是可能在转码中或者转码失败
 * ('on-error') 上传失败, 包含类型与大小超出限制
 */

export default defineComponent({
    props: {
        // 限制上传的文件类型
        acceptTypes: {
            type: Array,
            default: () => []
        },
        // 限制上传的文件大小
        acceptSize: {
            type: Number,
            default: Infinity
        },
        // 文件上传数量限制
        maxCount: {
            type: Number,
            default: Infinity
        },
        // 是否开启图片多选，部分安卓机型不支持
        multiple: {
            type: Boolean,
            default: false
        }
    },
    components: {
        AppUploader
    },
    setup(props, { emit, expose }) {
        const store = useStore();
        let uploadClient = null;
        const pollingTimer = ref(null);
        // allow upload file type
        const accept = computed(() => {
            if (props.acceptTypes.length) {
                return props.acceptTypes.map((ext) => '.' + ext).join(',');
            }

            return '*';
        });

        const uploaderAccept = computed(() => {
            if (Android.value) {
                return '*';
            } else {
                return accept.value
            }
        });
        
        // const isApp = computed(() => {
        //     return store.state.curUserAgent?.isApp;
        // });

        const Android = computed(() => {
            return isAndroid();
        });
        console.log('isAndroid()=====>', isAndroid())
        /* File Queue */
        const fileQueue = ref([]);
        watch(
            fileQueue,
            (queue) => {
                emit('update-file-list', queue);
                const isProcessing = queue.some(
                    (item) => item.status === Status.Processing
                );
                if (isProcessing) return;

                next();
            },
            { deep: true }
        );
        let ToastNode = null;

        function next() {
            // next.
            const order = fileQueue.value.findIndex(
                (item) => item.status === Status.Prepare
            );
            const uploadFile = fileQueue.value[order];

            if (uploadFile) {
                uploadFile.status = Status.Processing;
                fileQueue.value.splice(order, 1, uploadFile); // update
                setTimeout(() => {
                    ToastNode = Toast.loading({
                        message: '加载中...',
                        forbidClick: true,
                        duration: 0
                    });
                }, 0);
                upload(uploadFile);
            }
        }
        // update upload file status in file queue.
        function updateUploadFileStatus(id, status, progress) {
            const order = fileQueue.value.findIndex((item) => item.id === id);
            const uploadFile = fileQueue.value[order];

            if (uploadFile) {
                // update
                switch (status) {
                    case Status.Remove:
                        if (uploadFile.status === Status.Processing) {
                            cancelUpload();
                        }
                        fileQueue.value.splice(order, 1);
                        return;

                    case Status.Processing:
                        uploadFile.progress = progress || 0;
                        break;
                }

                uploadFile.status = status;
                fileQueue.value.splice(order, 1, uploadFile);
            }
        }

        /* Upload */
        function upload(uploadFile) {
            const { file, id } = uploadFile;
            const callback = {
                onProgress,
                onSuccess,
                onError
            };

            emit('update-file', uploadFile);

            uploadClient.start(file, id, callback);
        }
        function cancelUpload() {
            if (uploadClient) {
                uploadClient.stop();
            }
        }

        function onProgress(payload) {
            const { id, progress } = payload;
            const percent = Math.floor(progress.percent * 100) / 100;

            // processing
            updateUploadFileStatus(id, Status.Processing, percent);
        }
        function onSuccess(payload) {
            const { id, data } = payload;
            // success
            updateUploadFileStatus(id, Status.Success);
            // emit('on-success', data);
            asyncSuccess(data);
            // no need publish material??
        }

        async function asyncSuccess(file) {
            await publishMaterial(file);
        }

        function publishMaterial(data) {
            G_transmit('materialPublish', {
                    name: 'materialPublish',
                    data: {
                        materialFullName: data.name,
                        materialHash: data.hash,
                        materialSize: data.size,
                        materialUrl: data.url,
                        ispType: data.ispType
                    }
                })
                .then((res) => {
                    let resData = res.data || {};
                    // 上传成功, 有素材id但是可能在转码中或者转码失败
                    // emit('on-success', resData.materialId, {
                    //     materialFullName: data.name,
                    //     materialHash: data.hash,
                    //     materialSize: data.size,
                    //     materialUrl: data.host + '/' + data.url,
                    //     materialId: resData.materialId
                    // });
                    getMaterialListByIds([resData.materialId]);
                })
                .catch((error) => {
                    ToastNode && ToastNode.clear();
                    emit('on-error', error);
                });
        }
        function getMaterialListByIds(ids) {
            G_transmit('materialList', {
                    name: 'materialList',
                    data: {
                        materialIds: ids
                    }
                })
                .then(({ data }) => {
                    console.log('data0', data)
                    ToastNode && ToastNode.clear();
                    // let file = (data.rows && data.rows[0]) || {};
                    // let materialStatus = file.materialStatus || '';
                    emit('on-success', ids, data);
                    // if (materialStatus === 'usable') {
                    //     // 上传成功
                    //     clear();
                    //     emit('on-success', file);
                    //     return;
                    // }
                    // if (materialStatus === 'failed') {
                    //     clear();
                    //     emit('on-success', file);
                    // }
                })
                .catch((error) => {
                    ToastNode && ToastNode.clear();
                    emit('on-error', error);
                });
        }
        // 轮询
        async function polling(id) {
            clear();
            pollingTimer.value = setInterval(
                () => getMaterialListByIds(id),
                3000
            );
        }
        function clear() {
            if (pollingTimer.value) {
                clearInterval(pollingTimer.value);
            }
        }
        function onError(payload) {
            const { id, info } = payload;
            // error
            updateUploadFileStatus(id, Status.Error);
            emit('on-error', info);

            // no permission
            if (info.code === 401) {
                uploadClient = null;
            }
        }

        /* re-upload 重新上传 */
        async function reUploadByKey(id) {
            if (uploadClient == null) {
                uploadClient = await createUploader();
            }

            updateUploadFileStatus(id, Status.Prepare);
        }
        /* Remove 从上传队列中移除文件 */
        function removeUploadFileFromTheQueue(id) {
            updateUploadFileStatus(id, Status.Remove);
        }

        /* File Input */
        const fileInputRef = ref();
        function onChangeFileHandler(e) {
            const input = e.currentTarget;
            const files = input.files;
            if (files) {
                const uploadFileList = fileCheckAndFilter(files);
                if (uploadFileList) {
                    fileQueue.value = fileQueue.value.concat(uploadFileList);
                }
            }

            input.value = '';
        }
        async function handleUpload() {
            if (uploadClient == null) {
                uploadClient = await createUploader();
            }

            fileInputRef.value.click();
        }

        /* File Check */
        // 检查文件类型和大小是否超出限制，不符合的文件将被过滤掉
        function fileCheckAndFilter(files) {
            if (files) {
                let fileList = Array.prototype.map.call(files, (file) => file);
                // check file type
                fileList = checkFileType(fileList);

                // check file size
                fileList = checkFileSize(fileList);

                return fileList.map((file) => genUploadFile(file));
            }
        }
        function checkFileType(files) {
            const limitType = props.acceptTypes;
            const errorTypeList = [];

            const fileList = files.filter((file) => {
                const fileType = getFileSuffix(file);
                if (limitType.includes(fileType)) {
                    return true;
                } else {
                    errorTypeList.push(file);
                    return false;
                }
            });

            if (errorTypeList.length) {
                emit('on-error', {
                    code: 1001,
                    message: '文件格式错误'
                });
                // emit('on-error', {
                //     code: 1001,
                //     file: errorTypeList
                // });
            }

            return fileList;
        }
        function checkFileSize(files) {
            const limitSize = props.acceptSize;
            const errorSizeList = [];

            const fileList = files.filter((file) => {
                const fileSize = file.size;
                if (fileSize <= limitSize) {
                    return true;
                } else {
                    errorSizeList.push(file);
                    return false;
                }
            });

            if (errorSizeList.length) {
                // emit('on-error', {
                //     code: 1002,
                //     file: errorSizeList
                // });

                emit('on-error', {
                    code: 1001,
                    message: `上传失败，文件大小不能超过${formatFileSize(
                        props.acceptSize
                    )}`
                });
            }

            return fileList;
        }
        // 生成待上传文件的结构
        function genUploadFile(file) {
            return {
                progress: 0,
                status: Status.Prepare,
                file,
                id: uuid()
            };
        }

        // 文件读取前的回调函数，返回 false 可终止文件读取， 支持返回 Promise
        const onBeforeRead = async (file, detail) => {
            emit('on-before-upload', file);
            if (uploadClient == null) {
                uploadClient = await createUploader();
            }
        };
        // 文件读取完成后的回调函数
        const onAfterRead = (file) => {
            let uploadFileList = [];
            if (Object.prototype.toString.call(file) === '[object Array]') {
                // 批量上传个数>1
                uploadFileList = file.map((file) => file.file);
            } else {
                // 单个上传
                uploadFileList.push(file.file);
            }
            if (uploadFileList) {
                uploadFileList = fileCheckAndFilter(uploadFileList);
                fileQueue.value = fileQueue.value.concat(uploadFileList);
            }
        };

        const onAppSuccess = (materials) => {
            console.log('materials', materials)
            let ids = materials.map((item) => item.materialId);
            getMaterialListByIds(ids)
        };

        onMounted(() => {});

        expose({
            removeUploadFileFromTheQueue,
            reUploadByKey
        });
        return {
            fileInputRef,
            accept,
            onChangeFileHandler,
            handleUpload,
            onBeforeRead,
            onAfterRead,
            isApp,
            onAppSuccess,
            uploaderAccept
        };
    }
});
</script>

<style lang="scss" scoped></style>
